﻿#region << 文件说明 >>

/*----------------------------------------------------------------
 * 命名空间：Vampirewal.BlogCore
 * 唯一标识：1d0fc02a-27f2-4bed-9b60-10a0e0f40edf
 * 文件名：BlogCoreConfig
 *
 * 创建者：杨程
 * 电子邮箱：235160615@qq.com
 * 创建时间：2024/6/13 16:14:47
 * 版本：V1.0.0
 * 描述：
 *
 * ----------------------------------------------------------------
 * 修改人：
 * 时间：
 * 修改说明：
 *
 * 版本：V1.0.1
 *----------------------------------------------------------------*/

#endregion << 文件说明 >>

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Builder;

namespace Vampirewal.BlogCore;

/// <summary>
/// 配置
/// </summary>
internal sealed class BlogCoreConfig
{
    internal BlogCoreConfig()
    {
    }

    internal WebApplicationBuilder _builder { get; set; }

    internal WebApplication _webApplication { get; set; }

    /// <summary>
    /// 页面权限验证
    /// </summary>
    public event OnLoginAuthCheck OnLoginAuth;

    /// <summary>
    /// 页面响应中
    /// </summary>
    public event OnHtmlBeforeLoadEventHandler OnHtmlBeforeLoad;

    /// <summary>
    /// 页面加载后
    /// </summary>
    public event OnHtmlAfterLoadedEventHandler OnHtmlAfterLoaded;

    /// <summary>
    /// 配置中间件
    /// </summary>
    /// <param name="app"></param>
    /// <returns></returns>
    /// <exception cref="Exception"></exception>
    public BlogCoreConfig Configure(Action<WebApplication>? app)
    {
        app?.Invoke(_webApplication);

        _webApplication.UseStaticFiles();

        //进入主页
        _webApplication.MapGet("/",  async (HttpRequest request) =>
        {
            _htmlConfig.LocalHost = App.GetLocalhost(request);

            OnHtmlBeforeLoad?.Invoke(request);

            if (_htmlConfig.LoginAuthCheck)
            {
                request.Cookies.TryGetValue("token", out var value);

                if (string.IsNullOrEmpty(value))
                {
                    var loginHtml= _htmlConfig.GetLoginHtml();

                    return await Task.FromResult(Results.Content(loginHtml, "text/html"));
                }
                else
                {
                    var check= _htmlConfig.ValidateToken(value);

                    if (!check)
                    {
                        var loginHtml = _htmlConfig.GetLoginHtml();

                        return await Task.FromResult(Results.Content(loginHtml, "text/html"));
                    }
                }

            }

            var html = _htmlConfig.ToString();

            OnHtmlAfterLoaded?.Invoke(request, html);

            return await Task.FromResult(Results.Content(html, "text/html"));
        });

        _webApplication.MapGet("/login", ([FromQuery]string username,[FromQuery] string password) =>
        {
            var check= OnLoginAuth.Invoke(username, password);

            if (check)
            {
                var token= _htmlConfig.GenerateToken();

                return Results.Ok(new
                {
                    Token = token
                });
            }
            else
            {
                return Results.Unauthorized();
            }

        });

        //获取图片等资源
        _webApplication.MapGet("/assets/{file}", async (HttpRequest request) =>
        {
            string filePath = $"{App.RootPath}{request.Path}";

            return await GetFile(filePath);
        });

        _webApplication.MapGet("/assets/dist/{file}", async (HttpRequest request) =>
        {
            string filePath = $"{App.RootPath}{request.Path}";

            
            return await GetFile(filePath);
        });

        _webApplication.MapGet("/Resource/{file}",  async (HttpRequest request,string file) =>
        {
            return await GetResourceContent(file);
        });



        //获取文章明细
        _webApplication.MapGet("/api/getDetail/{id}", async (HttpRequest request,string id) =>
        {
            try
            {
                if (_htmlConfig.PageCacheDic.TryGetValue(id, out var html))
                {
                    return await Task.FromResult(Results.Content(html, "text/html"));
                }
                else
                {
                    if (_htmlConfig.PageDic.TryGetValue(id, out var page))
                    {
                        return await Task.FromResult(Results.Content(page.ToHtml(), "text/html"));
                    }
                }

                return await Task.FromResult(Results.NotFound());
            }
            catch (Exception ex)
            {
                return await Task.FromResult(Results.BadRequest(ex.Message));
            }
        });

        //按钮点击事件
        _webApplication.MapPost("/api/click/{btnNo}", async (HttpRequest request, string btnNo) =>
        {
            try
            {
                using var streamReader = new StreamReader(request.Body, leaveOpen: true);
                string body = await streamReader.ReadToEndAsync();

                var result = VampirewalMessenger.GetInstance().Send(btnNo, body);

                if (result is IActionResult)
                {
                    return await Task.FromResult(result);
                }

                if (App.JsonOptions == null)
                    App.SetJsonOptions(null);

                return await Task.FromResult(Results.Json(result, App.JsonOptions, "application/json", 200));
            }
            catch (Exception ex)
            {
                return await Task.FromResult(Results.BadRequest(ex.Message));
            }
        });

        return this;
    }

    private async Task<IResult> GetFile(string filePath)
    {
        if (File.Exists(filePath))
        {
            string extension = Path.GetExtension(filePath);

            return await Task.FromResult(Results.File(File.ReadAllBytes(filePath), GetContentType(extension)));
        }

        return await Task.FromResult(Results.NotFound());
    }

    private async Task<IResult> GetResourceContent(string resourceName)
    {
        var assembly = Assembly.GetExecutingAssembly();
        string[] resourceNames = assembly.GetManifestResourceNames();

        var file = resourceNames.FirstOrDefault(a => a.EndsWith(resourceName));

        if (!string.IsNullOrEmpty(file))
        {
            string extension = Path.GetExtension(file);

            using (Stream? stream = assembly.GetManifestResourceStream(file))
            {
                if (stream != null)
                {
                    byte[] buffer = new byte[stream.Length];
                    await stream.ReadAsync(buffer, 0, buffer.Length);

                    return await Task.FromResult( Results.File(buffer, GetContentType(extension)));
                }

            }
        }

        return await Task.FromResult( Results.NotFound());

    }

    /// <summary>
    /// 这里可以添加自定义的MapGet等MiniApi
    /// </summary>
    /// <param name="endpoint"></param>
    /// <returns></returns>
    /// <exception cref="Exception"></exception>
    public BlogCoreConfig UseEndpoints(Action<IEndpointRouteBuilder>? endpoint)
    {
        endpoint?.Invoke(_webApplication);

        return this;
    }

    /// <summary>
    /// 配置html页面信息
    /// </summary>
    /// <param name="html"></param>
    /// <returns></returns>
    /// <exception cref="Exception"></exception>
    public BlogCoreConfig ConfigureHtmlCongfig(Action<HtmlConfig> html)
    {
        html?.Invoke(_htmlConfig);

        IsEditHtml = true;

        return this;
    }

    /// <summary>
    /// 是否配置Html信息
    /// </summary>
    internal bool IsEditHtml { get; private set; }

    /// <summary>
    /// 页面配置
    /// </summary>
    internal HtmlConfig _htmlConfig { get; set; }

    #region Tools

    /// <summary>
    /// 根据文件扩展名获取内容类型
    /// </summary>
    /// <param name="extension">文件扩展名</param>
    /// <returns></returns>
    internal string? GetContentType(string extension)
    {
        string reval = string.Empty;

        if (string.IsNullOrEmpty(extension))
            return null;

        switch (extension)
        {
            case ".htm":
                reval = "text/html";
                break;

            case ".html":
                reval = "text/html";
                break;

            case ".txt":
                reval = "text/plain";
                break;

            case ".css":
                reval = "text/css";
                break;

            case ".png":
                reval = "image/png";
                break;

            case ".gif":
                reval = "image/gif";
                break;

            case ".jpg":
                reval = "image/jpg";
                break;

            case ".jpeg":
                reval = "image/jgeg";
                break;

            case ".zip":
                reval = "application/zip";
                break;

            case ".ico":
                reval = "image/x-icon";
                break;

            case ".js":
                reval = "application/javascript";
                break;
            
        }
        return reval;
    }

    #endregion

    /// <summary>
    /// 注册配置
    /// </summary>
    internal void RegisterOptions()
    {
        var configurationBuilder = new ConfigurationBuilder().SetBasePath($"{AppDomain.CurrentDomain.BaseDirectory}Configuration");

        var types = App.EffectiveTypes.Where(w => w.GetInterfaces().Where(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IBlogOption<>)).ToList().Any()).ToArray();

        List<object> list = new List<object>();

        foreach (var option in types)
        {
            string optionName = option.Name.Replace("Options", "");

            configurationBuilder.AddJsonFile($"{optionName}.json");

            var op = Activator.CreateInstance(option);

            _builder.Services.AddSingleton(typeof(IBlogOption<>).MakeGenericType(option), op);

            list.Add(op);
        }

        App.Configuration = configurationBuilder.Build();

        foreach (var item in list)
        {
            App.Configuration.Bind(item);
        }
    }
}

/// <summary>
/// 页面权限验证委托
/// </summary>
/// <param name="username">用户名</param>
/// <param name="password">密码</param>
/// <returns></returns>
internal delegate bool OnLoginAuthCheck(string username,string password);

/// <summary>
/// html加载前的委托
/// </summary>
/// <param name="request"></param>
internal delegate void OnHtmlBeforeLoadEventHandler(HttpRequest request);

/// <summary>
/// html加载后的委托
/// </summary>
/// <param name="request"></param>
/// <param name="html"></param>
internal delegate void OnHtmlAfterLoadedEventHandler(HttpRequest request, string html);